package com.mas.session.state;

import com.mas.common.AgentUtil;
import com.mas.session.MonitorSession;
import com.mas.session.Session;
import com.mas.strategey.Proposal;

import jade.core.behaviours.Behaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

public class WaitingForProposalResState extends AbstractState {

	private Proposal proposal;

	public WaitingForProposalResState(Session session) {
		super(session);
	}

	public void waitForProposalResponse(ACLMessage message) {
		session.logInfo("WaitingForProposalResState.waitForProposalResponse()");
		session.getAgent().addBehaviour(
				new WaitForProposalRspBehaviour(this, message));
	}

	/**
	 * @return the proposal
	 */
	public Proposal getProposal() {
		return proposal;
	}

	/**
	 * @param proposal
	 *            the proposal to set
	 */
	public void setProposal(Proposal proposal) {
		this.proposal = proposal;
	}

	class WaitForProposalRspBehaviour extends Behaviour {

		private WaitingForProposalResState waitingForProposalResState;

		private ACLMessage message;

		private boolean doneInd;

		public WaitForProposalRspBehaviour(
				WaitingForProposalResState waitingForProposalResState,
				ACLMessage message) {
			super();
			this.waitingForProposalResState = waitingForProposalResState;
			this.message = message;
			doneInd = false;
		}

		public void action() {
			ACLMessage proposalResMsg = myAgent
					.receive(prepareMessageTemplate());
			if (proposalResMsg == null) {
				System.out
						.println("WaitForProposalRspBehaviour->message does not match, blocking..."
								+ myAgent.getName() + "-" + session.getName());
				block();
			} else {

				if (proposalResMsg.getPerformative() == ACLMessage.ACCEPT_PROPOSAL) {
					// if this state is being called by the monitor
					if (waitingForProposalResState.session instanceof MonitorSession) {

						ProcessAcceptState state = (ProcessAcceptState) waitingForProposalResState.session
								.assignState(ProcessAcceptState.class.getName());
						state.setProposal(proposal);
						state.acceptProposalResponse(proposalResMsg);
					} else {
						// this is user.
						
						ExitState state = (ExitState) this.waitingForProposalResState.session
								.assignState(ExitState.class.getName());
						state.setProposal(proposal);
						session.setAccepted(true);
						state.exit(proposalResMsg,"Proposal accepted");
					}
				} else if (proposalResMsg.getPerformative() == ACLMessage.REJECT_PROPOSAL) {
					RejectExitState state = (RejectExitState) waitingForProposalResState.session
							.assignState(RejectExitState.class.getName());
					state.setProposal(proposal);
					state.rejectProposalResponse(proposalResMsg);
				} else if (proposalResMsg.getPerformative() == ACLMessage.PROPOSE) {
					// Get new proposal
					proposal = AgentUtil.readProposal(proposalResMsg.getContent());
					if ( proposal == null) {
						assignFailureState(message, "Expecting Proposal Object");
					}else{
						NewProposalProcessor state = (NewProposalProcessor) waitingForProposalResState.session
								.assignState(NewProposalProcessor.class
										.getName());
						waitingForProposalResState.session
								.setCurrentState(state);
						state.setProposal(proposal);
						waitingForProposalResState.session
								.processNewProposal(proposalResMsg);
					}

				} else {
					// cannot reach here.
					throw new RuntimeException(
							"Error, message can be one of the following: ACCEPT_PROPOSAL, "
									+ "REJECT_PROPOSAL,PROPOSEs");
				}

				doneInd = true;
			}

		}

		private MessageTemplate prepareMessageTemplate() {

			MessageTemplate messageTemplate = MessageTemplate
					.or(
							MessageTemplate
									.MatchPerformative(ACLMessage.PROPOSE),
							MessageTemplate
									.or(
											MessageTemplate
													.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL),
											MessageTemplate
													.MatchPerformative(ACLMessage.REJECT_PROPOSAL)));

			messageTemplate = MessageTemplate.and(MessageTemplate.MatchConversationId(message
					.getConversationId()), messageTemplate);
			return messageTemplate;
		}

		public boolean done() {
			if (doneInd) {
				System.out.println("stop this behavior" + myAgent.getName()
						+ "-" + session.getName());
			}
			return doneInd;
		}


	}
}